package com.sh.data.engine.application.model.annotation;

import cn.hutool.core.collection.CollectionUtil;
import com.sh.data.engine.application.model.request.integration.DataSourceCreateRequest;
import com.sh.data.engine.common.enumDefinition.DSType;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.apache.commons.lang.StringUtils;

import java.util.List;
import java.util.Map;

/**
 * @author: mengzheng.mhc
 * @date: 2024/12/20 16:50
 */
public class DataSourceConditionalFieldsValidator implements ConstraintValidator<DataSourceConditionalFields, DataSourceCreateRequest> {

    // 校验逻辑的映射表
    private static final Map<DSType, Validator> VALIDATORS = Map.of(
        DSType.Hive, dsConfig -> validateSingleAddress(dsConfig) &&
            StringUtils.isNotBlank(dsConfig.getUsername()) &&
            StringUtils.isNotBlank(dsConfig.getPassword()) &&
            StringUtils.isNotBlank(dsConfig.getDbName()) &&
            StringUtils.isNotBlank(dsConfig.getHiveSiteAddress()) &&
            StringUtils.isNotBlank(dsConfig.getOriginalFilename()),

        DSType.Kafka, DataSourceConditionalFieldsValidator::validateAllAddresses,

        DSType.MQTT, DataSourceConditionalFieldsValidator::validateAllAddresses,

        DSType.HBase, DataSourceConditionalFieldsValidator::validateAllAddresses,

        DSType.Mongodb, dsConfig -> validateSingleAddress(dsConfig) &&
            StringUtils.isNotBlank(dsConfig.getDbName()),

        DSType.IoTDB, dsConfig -> validateAllAddresses(dsConfig) &&
            StringUtils.isNotBlank(dsConfig.getUsername()) &&
            StringUtils.isNotBlank(dsConfig.getPassword()),

        DSType.InfluxDB, dsConfig -> validateSingleAddress(dsConfig) &&
            StringUtils.isNotBlank(dsConfig.getApiToken()) &&
            StringUtils.isNotBlank(dsConfig.getOrgName()) &&
            StringUtils.isNotBlank(dsConfig.getDbName())
    );

    @Override
    public boolean isValid(DataSourceCreateRequest dataSourceCreateRequest, ConstraintValidatorContext constraintValidatorContext) {
        if (dataSourceCreateRequest == null) {
            return true;
        }

        DSType dsType = dataSourceCreateRequest.getDsType();
        if (dsType == null) {
            return false;
        }

        DataSourceCreateRequest.DSConfig dsConfig = dataSourceCreateRequest.getDsConfig();
        if (dsConfig == null || CollectionUtil.isEmpty(dsConfig.getAddress())) {
            return false;
        }

        // RDBMS 类型特殊处理
        if (DSType.isRdbms(dsType.name())) {
            return validateRdbms(dsType, dsConfig);
        }

        // 根据数据源类型执行校验逻辑
        Validator validator = VALIDATORS.get(dsType);
        return validator == null || validator.validate(dsConfig);
    }

    // 校验 RDBMS 类型数据源
    private boolean validateRdbms(DSType dsType, DataSourceCreateRequest.DSConfig dsConfig) {
        if (dsType == DSType.Oracle && dsConfig.getOracleConnectionType() == null) {
            return false;
        }

        if (!validateSingleAddress(dsConfig)) {
            return false;
        }

        return StringUtils.isNotBlank(dsConfig.getUsername()) &&
            StringUtils.isNotBlank(dsConfig.getPassword()) &&
            StringUtils.isNotBlank(dsConfig.getDbName());
    }

    // 校验工具方法
    private static boolean validateSingleAddress(DataSourceCreateRequest.DSConfig dsConfig) {
        List<DataSourceCreateRequest.Address> addresses = dsConfig.getAddress();
        if (addresses.size() != 1) {
            return false;
        }
        return validateAddress(addresses.get(0));
    }

    private static boolean validateAllAddresses(DataSourceCreateRequest.DSConfig dsConfig) {
        return dsConfig.getAddress().stream().allMatch(DataSourceConditionalFieldsValidator::validateAddress);
    }

    private static boolean validateAddress(DataSourceCreateRequest.Address address) {
        return StringUtils.isNotBlank(address.getHost()) && address.getPort() != null;
    }

    @FunctionalInterface
    private interface Validator {
        boolean validate(DataSourceCreateRequest.DSConfig dsConfig);
    }
}
